package cn.tedu.mall.front.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 存储缓存对象
 * 使用泛型T定义缓存类型
 * 集成所有缓存的功能，集中使用这个类来解决
 * 其他需要使用缓存功能的业务，只需要继承并定义泛型类型就可以了
 */
public class FrontCacheServiceImpl<T> {

    @Autowired
    protected RedisTemplate redisTemplate;

    // 单个对象的存储和获取
    public void setToRedis(String key, T value) {
        this.setToRedis(key, value, null, null);
    }

    public void setToRedis(String key, T value, Long expiredTime, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, expiredTime, timeUnit);
    }

    public T getFromRedis(String key) {
        return (T) redisTemplate.opsForValue().get(key);
    }

    // list对象的存储和获取
    public void setListToRedis(String key, List<T> value) {
        this.setListToRedis(key, value, null, null);
    }

    public void setListToRedis(String key, List<T> value, Long expiredTime, TimeUnit timeUnit) {
        redisTemplate.opsForList().leftPushAll(key, value);
        setExpire(key, expiredTime, timeUnit);
    }

    public List<T> getListFromRedis(String key) {
        if (redisTemplate.hasKey(key)) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
        return null;
    }

    public void deleteFromRedis(String key) {
        redisTemplate.delete(key);
    }

    public void deleteFromRedis(List<String> keys) {
        redisTemplate.delete(keys);
    }

    // Hash对象的存储和获取
    public void setHashToRedis(String key, String hashKey, T value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }
    public Boolean setHashToRedis(String key, String hashKey, T value, long time) {
        redisTemplate.opsForHash().put(key, hashKey, value);
        return expire(key, time);
    }

    public T getHashFromRedis(String key, String hashKey) {
        return (T) redisTemplate.opsForHash().get(key, hashKey);
    }

    public void deleteHashFromRedis(String key, String hashKey) {
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    public void deleteHashFromRedis(String key) {
        redisTemplate.delete(key);
    }

    // 设置过期时间
    public void setExpire(String key, Long expiredTime, TimeUnit timeUnit) {
        if (expiredTime != null && timeUnit != null) {
            redisTemplate.expire(key, expiredTime, timeUnit);
        }
    }

    public Boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    // 分布式锁 cyclicTryLock 循环5次抢锁，没抢到就睡眠5秒
    public boolean cyclicTryLock(String lockKey, String randCode) {
        int tryTimes = 0;
        while (tryTimes < 5) {
            try {
                Boolean hadLock = redisTemplate.opsForValue().setIfAbsent(lockKey, randCode, 10, TimeUnit.SECONDS);
                if (hadLock) {
                    return true;
                }
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tryTimes++;
        }
        return false;
    }

    // 分布式锁 tryLock
    public boolean tryLock(String lockKey, String randCode) {
        return redisTemplate.opsForValue().setIfAbsent(lockKey, randCode, 10, TimeUnit.SECONDS);
    }

    // 分布式锁 释放锁
    public void releaseLock(String lockKey, String randCode) {
        if (Objects.equals(redisTemplate.opsForValue().get(lockKey), randCode)) {
            redisTemplate.opsForValue().getOperations().delete(lockKey);
        }
    }

}
